package com.example.demo7executorService;

import java.util.concurrent.*;

/**
 * 目标：创建线程池对象来使用
 */
public class ExecutorServiceDemo1 {
    public static void main(String[] args) {
        // 1.使用线程池的实现类ThreadPoolExecutor声明七个参数来创建线程池对象。
        ExecutorService pool = new ThreadPoolExecutor(3, 5,
                10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
        /*
        任务拒绝策略
        ThreadPoolExecutor.AbortPolicy()	        丢弃任务并抛出RejectedExecutionException异常。是默认的策略
        ThreadPoolExecutor. DiscardPolicy()	        丢弃任务，但是不抛出异常，这是不推荐的做法
        ThreadPoolExecutor. DiscardOldestPolicy()	抛弃队列中等待最久的任务 然后把当前任务加入队列中
        ThreadPoolExecutor. CallerRunsPolicy()	    由主线程负责调用任务的run()方法从而绕过线程池直接执行
         */
        /*
        参数一：corePoolSize : 指定线程池的核心线程的数量。
        参数二：maximumPoolSize：指定线程池的最大线程数量。
        参数三：keepAliveTime ：指定临时线程的存活时间。
        参数四：unit：指定临时线程存活的时间单位(秒、分、时、天）
        参数五：workQueue：指定线程池的任务队列。 可以创建基于数组的队列 也可以创建基于链表的队列
        参数六：threadFactory：指定线程池的线程工厂。
        参数七：handler：指定线程池的任务拒绝策略（线程都在忙，任务队列也满了的时候，新任务来了该怎么处理）
         */

        // 2.使用线程池处理任务！看会不会复用线程？
        Runnable target = new MyRunnable();
        pool.execute(target); // 提交第1个任务 创建第1个线程 自动启动线程处理这个任务
        pool.execute(target); // 提交第2个任务 创建第2个线程 自动启动线程处理这个任务
        pool.execute(target); // 提交第2个任务 创建第3个线程 自动启动线程处理这个任务
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
        /*
        什么时候开始创建临时线程？
          新任务提交时发现核心线程都在忙，任务队列也满了，并且还可以创建临时线程，此时才会创建临时线程。
        什么时候会拒绝新任务？
          核心线程和临时线程都在忙，任务队列也满了，新的任务过来的时候才会开始拒绝任务。
         */
        pool.execute(target); // 到了临时线程的创建时机了
        pool.execute(target); // 到了临时线程的创建时机了
        pool.execute(target); // 到了任务拒绝策略了，忙不过来

        // 3.关闭线程池 ：一般不关闭线程池
        // pool.shutdown(); // 等所有任务执行完毕后再关闭线程池！
        // pool.shutdownNow(); // 立即关闭，不管任务是否执行完毕！
    }
}
